#pragma once

#define JLIB_NS jlib
#define OPEN_JLIB_NS namespace JLIB_NS {
#define CLOSE_JLIB_NS }
#define USE_JLIB_NS using namespace JLIB_NS;

#define LIKE(expr) __builtin_expect((expr), 1)
#define UNLIKE(expr) __builtin_expect((expr), 0)

#if defined(__clang__)
  #if __has_feature(cxx_rtti)
    #define RTTI_ENABLED
  #endif
#elif defined(__GNUC__)
  #if defined(__GXX_RTTI)
    #define RTTI_ENABLED
  #endif
#elif defined(_MSC_VER)
  #if defined(_CPPRTTI)
    #define RTTI_ENABLED
  #endif
#endif

// nothing
#define NOTHING(...)

// drop anything after first comma
#define FIRST_(_, ...) _
// package FIRST_
#define FIRST(_) FIRST_(_)

// drop anything before first comma
#define NOFIRST(_, ...) __VA_ARGS__

// concatenate arg1 and arg2
#define CONCAT_(_1, _2) _1##_2
// package CONCAT_
#define CONCAT(_1, _2) CONCAT_(_1, _2)

// select arg1
#define SELECT(_1, _2) _1

// select arg2
#define SELECT_(_1, _2) _2

// if has __VA_ARGS__ then $HAS, else $NO
#define IFARG(HAS, NO, ...) CONCAT(SELECT, FIRST(NOFIRST(,,##__VA_ARGS__ _)))(HAS, NO)

#define ARGN_(_, _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_N,...) _N

// number of __VA_ARGS__
#define ARGN(...) ARGN_(_, __VA_ARGS__,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

// splice token
#define SPLICE_TOKEN_(left, separator, right) left##separator##right
// splice token
#define SPLICE_TOKEN(sep, ...) IFARG(, ##__VA_ARGS__)


#define EVAL_0(name, ...)
#define EVAL_1(name, ...) name(FIRST_(__VA_ARGS__))
#define EVAL_2(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_1(name, NOFIRST(__VA_ARGS__))
#define EVAL_3(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_2(name, NOFIRST(__VA_ARGS__))
#define EVAL_4(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_3(name, NOFIRST(__VA_ARGS__))
#define EVAL_5(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_4(name, NOFIRST(__VA_ARGS__))
#define EVAL_6(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_5(name, NOFIRST(__VA_ARGS__))
#define EVAL_7(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_6(name, NOFIRST(__VA_ARGS__))
#define EVAL_8(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_7(name, NOFIRST(__VA_ARGS__))
#define EVAL_9(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_8(name, NOFIRST(__VA_ARGS__))
#define EVAL_10(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_9(name, NOFIRST(__VA_ARGS__))
#define EVAL_11(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_10(name, NOFIRST(__VA_ARGS__))
#define EVAL_12(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_11(name, NOFIRST(__VA_ARGS__))
#define EVAL_13(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_12(name, NOFIRST(__VA_ARGS__))
#define EVAL_14(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_13(name, NOFIRST(__VA_ARGS__))
#define EVAL_15(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_14(name, NOFIRST(__VA_ARGS__))
#define EVAL_16(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_15(name, NOFIRST(__VA_ARGS__))
#define EVAL_17(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_16(name, NOFIRST(__VA_ARGS__))
#define EVAL_18(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_17(name, NOFIRST(__VA_ARGS__))
#define EVAL_19(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_18(name, NOFIRST(__VA_ARGS__))
#define EVAL_20(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_19(name, NOFIRST(__VA_ARGS__))
#define EVAL_21(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_20(name, NOFIRST(__VA_ARGS__))
#define EVAL_22(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_21(name, NOFIRST(__VA_ARGS__))
#define EVAL_23(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_22(name, NOFIRST(__VA_ARGS__))
#define EVAL_24(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_23(name, NOFIRST(__VA_ARGS__))
#define EVAL_25(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_24(name, NOFIRST(__VA_ARGS__))
#define EVAL_26(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_25(name, NOFIRST(__VA_ARGS__))
#define EVAL_27(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_26(name, NOFIRST(__VA_ARGS__))
#define EVAL_28(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_27(name, NOFIRST(__VA_ARGS__))
#define EVAL_29(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_28(name, NOFIRST(__VA_ARGS__))
#define EVAL_30(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_29(name, NOFIRST(__VA_ARGS__))
#define EVAL_31(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_30(name, NOFIRST(__VA_ARGS__))
#define EVAL_32(name, ...) EVAL_1(name, FIRST_(__VA_ARGS__)) EVAL_31(name, NOFIRST(__VA_ARGS__))

// call the macro named $name with each parameter
#define EVAL_ARGN(name, ...) CONCAT(EVAL_, ARGN(__VA_ARGS__))(name, __VA_ARGS__)

